package com.moon.game.manager;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;

import com.moon.game.constants.Constants;
import com.moon.game.server.ResetThread;
import com.moon.game.service.PlayerService;
import com.moon.game.util.GDateUtils;
import com.moon.game.vos.PlayerVo;

public class PlayerMG {
	private static Logger log = Logger.getLogger(PlayerMG.class);
	private static Logger logLogin = Logger.getLogger(Constants.LOG_LOGIN);

	// 在线列表<PlayerId,PlayerVo>
	private Map<String, PlayerVo> onlineMap = new ConcurrentHashMap<String, PlayerVo>();
	private Map<Integer, LinkedList<PlayerVo>> sexMap = new HashMap<Integer, LinkedList<PlayerVo>>();

	// 玩家状态锁(保证每次同一个ID只有一个玩家进入到游戏)
	private ConcurrentHashMap<String, Long> lockCache = new ConcurrentHashMap<String, Long>();
	public static PlayerMG instance = new PlayerMG();
	private static Map<Integer, List<String>> faces = new HashMap<Integer, List<String>>();

	/**
	 * 锁定player
	 * 
	 * @param playerId
	 */
	public void lock(String playerId) {
		if (StringUtils.isNotBlank(playerId)) {
			lockCache.put(playerId, System.currentTimeMillis());
		}
	}
	
	public void access(PlayerVo playerVo) {
		// 存在更新访问时间
		Calendar calendar = Calendar.getInstance();
		int today = calendar.get(Calendar.DAY_OF_YEAR);
		PlayerVo checkPlayer = PlayerMG.instance.getPlayer(playerVo.getId());
		// 更新访问时间
		if (checkPlayer != null) {
			calendar.setTime(new Date(playerVo.getAccessTime() * 1000l));//设置上次的访问时间
			playerVo.setAccessTime(GDateUtils.now());//更新访问时间
		}else {
			calendar.setTime(new Date(playerVo.getAccessTime() * 1000l));
			
			// 更新Profile数据到PlayerVo
			int now = GDateUtils.now();
			playerVo.setLastLoginTime(playerVo.getLoginTime());
			playerVo.setLoginTime(now);
			playerVo.setAccessTime(now);
			playerVo.setStatus(Constants.STATUS_ONLINE);
			
			// 缓存玩家在线数据
			onlineMap.put(playerVo.getId(), playerVo);
			
			// TODO:检查装备位道具是否合法
//			checkUsedItem(PlayerVo);
			// 防骗子，过滤系字
			if (playerVo.getName().indexOf("系") != -1) {
				playerVo.setName(playerVo.getName().replaceAll("系", "*"));
			}

			PlayerService.doUpdatePlayer(playerVo.getSid(), playerVo.getId(), playerVo);
//			UpdatePlayerThread.addSyncPlayerMap(playerVo);
			

			// 日志
			StringBuffer sb = new StringBuffer();
			sb.append("login:").append("|");
			sb.append(playerVo.getId()).append("|");
			sb.append(playerVo.getExp()).append("|");
			sb.append(playerVo.getMoney()).append("|");
			sb.append(playerVo.getGold()).append("|");
			sb.append(playerVo.getLevel()).append("|");
			sb.append(playerVo.getCurHp()).append("|");
			sb.append(playerVo.getHp()).append("|");
			sb.append(playerVo.getCurMp()).append("|");
			sb.append(playerVo.getMp()).append("|");
			sb.append(playerVo.getMaxRoom()).append("|");
			sb.append(playerVo.getBurden());
			logLogin.debug(sb.toString());
		
		}
		// 隔天设置
		if (today != calendar.get(Calendar.DAY_OF_YEAR)) {
			ResetThread.inst.addPlayer(playerVo.getId());
		}
	}

	/**
	 * 检查playerId是否可以使用
	 * 
	 * @param playerId
	 * @return
	 */
	public boolean checkLock(String playerId) {
		boolean ret = false;
		if (StringUtils.isNotBlank(playerId) && lockCache.containsKey(playerId)) {
			Long lastAccessTime = lockCache.get(playerId);
			if (lastAccessTime != null) {
				// 锁异常处理: 距离上次访问时间大于1秒钟自动解锁
				if (System.currentTimeMillis() - lastAccessTime > 1 * 1000) {
					unLock(playerId);
				} else {
					ret = true;
				}
			}
		}
		return ret;
	}

	/**
	 * 解锁
	 * 
	 * @param playerId
	 */
	public void unLock(String playerId) {
		lockCache.remove(playerId);
	}

	/**
	 * 初始化
	 */
	public void init() {

	}

	/**
	 * @return the faces
	 */
	public static final Map<Integer, List<String>> getFaces() {
		return faces;
	}

	public Map<String, PlayerVo> getOnlineMap() {
		return onlineMap;
	}

	/**
	 * @return the sexMap
	 */
	public final Map<Integer, LinkedList<PlayerVo>> getSexMap() {
		return sexMap;
	}

	/**
	 * 获取player
	 */
	public PlayerVo getPlayer(String playerId) {
		return onlineMap.get(playerId);
	}

	/**
	 * 在线
	 * 
	 * @return
	 */
	public boolean online(String playerId) {
		return getPlayer(playerId) != null;
	}

	/**
	 * 不在线
	 * 
	 * @return
	 */
	public boolean offline(String playerId) {
		return !online(playerId);
	}

	/**
	 * 玩家访问记录
	 * 
	 * @param req
	 * @param player
	 * @throws PpseaException
	 */
	/*public void access(RequestSession req, PlayerVo player) throws GException {
		final int now = GDateUtils.now();
		Calendar calendar = Calendar.getInstance();
		final int today = calendar.get(Calendar.DAY_OF_YEAR);
		calendar.setTime(new Date(player.getAccessTime() * 1000L));

		// 从腾讯登陆过来的认证信息
		String tokenKey = (String) req.getClientRequest().getVO(OpenSdkService.TOKEN_KEY);
		String tokenSecrect = (String) req.getClientRequest().getVO(OpenSdkService.TOKEN_SECRECT);
		String oid = (String) req.getClientRequest().getVO(OpenSdkService.OID);
		StringBuilder logMsg = new StringBuilder();
		logMsg.append("tx|" + player.getId() + "|" + tokenKey + "|" + tokenSecrect + ";");
		logMsg.append("game|" + player.getTokenKey() + "|" + player.getTokenSecrect() + "|" + player.getOid() + ";");
		if (StringUtils.isNotBlank(tokenKey) && StringUtils.isNotBlank(tokenSecrect)) {
			player.setTokenKey(tokenKey);
			player.setTokenSecrect(tokenSecrect);
		}

		if (StringUtils.isNotBlank(oid)) {
			player.setOid(oid);
		}

//		log.debug(logMsg.toString());
//		logMsg = null;

		if (offline(player.getId())) {// 离线玩家初次进入游戏 的处理
			player.setLastLoginTime(player.getLoginTime());
			player.setLoginTime(now);
			player.setStatus(ProtocolConstants.STATUS_ONLINE);
			onlineMap.put(player.getId(), player);// 缓存玩家在线数据(在线)
		}
		player.setAccessTime(now);
		if (today != calendar.get(Calendar.DAY_OF_YEAR)) {// 时间过期(隔天刷新玩家数据)
			ResetThread.inst.addPlayer(player.getId());
		}
	}*/

	/**
	 * 对离线用户进行同步数据
	 */
	public void logout() {
		log.info("star scan player");
		long start = System.currentTimeMillis();
		try {
			Map<String, PlayerVo> onlineMap = PlayerMG.instance.getOnlineMap();
			Map<String, PlayerVo> offlineMap = new ConcurrentHashMap<String, PlayerVo>();
			for (Map.Entry<String, PlayerVo> onlineEntry : onlineMap.entrySet()) {
				String playerId = onlineEntry.getKey();
				PlayerVo PlayerVo = onlineEntry.getValue();
				int accessTime = PlayerVo.getAccessTime();
				if ((GDateUtils.now() - accessTime) > Constants.TIME_LOGOUT) { // 15分钟不操作表示离线
					// 添加到离线map,用于更新player数据
					offlineMap.put(playerId, PlayerVo);
					onlineMap.remove(playerId);
				}
			}

			// logout
			syncPlayersOutline(offlineMap);
			offlineMap.clear();
		} catch (Exception e) {
			log.error("excecption scan:", e);
		}

		long end = System.currentTimeMillis();
		log.info("end scan card,use time:" + (end - start));
	}

	/**
	 * 同步player到Profile
	 * 
	 * @param map
	 */
	public void syncPlayersOutline(Map<String, PlayerVo> map) {
		try {
			for (Map.Entry<String, PlayerVo> entry : map.entrySet()) {
				String playerId = entry.getKey();
				PlayerVo player = entry.getValue();
				player.setStatus(Constants.STATUS_OFFLINE);
				PlayerService.doUpdatePlayer(player.getSid(), playerId, player); // 缓写开启同步Player

				// 日志
				StringBuffer sb = new StringBuffer();
				sb.append("logout").append("|");
				sb.append(playerId + "|");
				sb.append(GDateUtils.now() - player.getLoginTime()); // 在线时间
				logLogin.debug(sb.toString());
			}
		} catch (Exception e) {
			e.printStackTrace();
			log.error("sync player error!");
		}
	}
	
	/**
	 * 在线同步玩家
	 * 
	 * @param player
	 */
	public static void syncPlayersOnline(PlayerVo player) {
		PlayerService.updatePlayerLog(player);//打印人物相关信息日志
		PlayerService.doUpdatePlayer(player.getSid(), player.getId(), player);
//		UpdatePlayerThread.addSyncPlayerMap(player);
	}

	/**
	 * 获取在线符合要求的玩家(异性、等级范围内、数量)
	 * 
	 * @param player
	 * @param rangeLevel
	 * @param num
	 * @return
	 */
	public List<PlayerVo> getOnlinePlayers(final PlayerVo player, final int rangeLevel, final int num) {
		List<PlayerVo> players = new ArrayList<PlayerVo>();
		Map<String, PlayerVo> onlinePlayerMap = getOnlineMap();
		for (PlayerVo p : onlinePlayerMap.values()) {
			if (!p.getId().equals(player.getId()) && p.getSex() != player.getSex() && Math.abs(p.getLevel() - player.getLevel()) <= rangeLevel) {
				players.add(p);
			}
			if (players.size() >= num) {
				break;
			}
		}
		return players;
	}
}
